package Namensdienst;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;

/**
 * 
 * executes a Request given from the skeleton server
 *
 */
public class RequestExecuter implements Runnable{
	OutputStream out; 
	BufferedReader in;
	/**
	 * contains the information about the names
	 */
	HashMap<String, NameObject> obj_map;
	Socket mySock;
	InputStreamReader in_low;
	String ns_hostname;
	int ns_port;
	
	public RequestExecuter(Socket mySock, HashMap<String, NameObject> obj_map, String ns_hostname, int ns_port) {
		this.mySock = mySock;
		this.obj_map = obj_map;
		this.ns_hostname = ns_hostname;
		this.ns_port = ns_port;
	}
	
	@Override
	public void run() {
		String incoming = null;
		
		try {
			out = mySock.getOutputStream();
			in_low = new InputStreamReader(mySock.getInputStream());
			in = new BufferedReader(in_low);
			out = mySock.getOutputStream();
			
			incoming = in.readLine();
	        System.out.println("NS: incoming- "+incoming);
	        
	        //Split the incomming command string
	        String[] splitted;
	        if(incoming != null){
                splitted = incoming.split(":");
	        }else{
                splitted = new String[0];
                System.out.println("NS: nur null bekommen!");
	        }
	        
	        //delegate by the main command
	        if(splitted.length > 1){
	            if(splitted[0].equals("unbind") ){
	            	System.out.println("unbind");
	            	removeName(splitted[1]);
	            	
	            }else if(splitted[0].equals("rebind")){
	            	System.out.println("rebind");
	            	rebind(splitted);
	            	
	            }else if(splitted[0].equals("resolve")){
	            	System.out.println("resolve");
	            	resolve(splitted);
	            }
	            
	        }else{
	        	out.write("ERROR".getBytes());
	        	out.flush();
	        }
	        
	        //operation complete, close connections
	        out.flush();
	        mySock.close();
	        in.close();
	        out.close();
        
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	
	private void rebind(String[] splitted) throws IOException, ClassNotFoundException{
		//extract information of message
		Class<?> ObjClass = Class.forName(splitted[1]);
    	String obj_name = splitted[2];
    	String remoteHostIP = splitted[3];
    	int remotePort = 0;
    	try{
    		remotePort = Integer.parseInt(splitted[4]);
    	}catch(NumberFormatException e){
    		out.write("RemoteException:InvalidPort".getBytes());
    		return;
    	}
    	
    	//generate object for the map
    	NameObject no= new NameObject(ObjClass, remoteHostIP, remotePort);
    	synchronized (obj_map) {
    		obj_map.put(obj_name, no);
		}    	
    	
    	System.out.println("NS outgoing: OK");
    	out.write("OK".getBytes());
	}
	
	private void resolve(String[] splitted) {
		try {
			if(obj_map.containsKey(splitted[1])){
				//name found, send information for the stub
				String outg = "Class:"+obj_map.get(splitted[1]).getClass_o().getName()+":"+obj_map.get(splitted[1]).getIp()+":"+obj_map.get(splitted[1]).getPort()+"\n";
				System.out.println( "NS out: " + outg );
			 	
				System.out.println("NS outgoing: "+outg);
				out.write( outg.getBytes() );			
			  	out.flush();
			}else{
				//name not found
				System.out.println("NS outgoing: null");
				out.write( ("null" + "\n").getBytes() );
			    out.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void removeName(String name){
    	synchronized (obj_map) {
    		obj_map.remove(name);
		}        	
    }

}
